package com.cursino.wilson.game;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.NumberFormat;

import com.cursino.wilson.game.baccarat.Baccarat;
import com.cursino.wilson.game.baccarat.BaccaratResult;
import com.cursino.wilson.game.baccarat.BaccaratStats;
import com.cursino.wilson.game.baccarat.GameResult;
import com.cursino.wilson.game.card.Card;
import com.cursino.wilson.game.card.Hand;

/**
 * App to run and show results for the game.
 * @author <a href="mailto:"wilson.cursino@gmail.com"> Wilson Soethe Cursino </a>
 * @since 1.0
 */
public class PlayBaccarat {

    /**
     * I wish I could arrange it better....Simple presentation for the Baccarat game.
     * @param args
     * @throws FileNotFoundException
     */
    public static void main(String[] args) throws FileNotFoundException {
        long startTime = System.currentTimeMillis();
        PrintWriter out = new PrintWriter("result.txt");
        StringBuffer results = new StringBuffer();

        results.append("**************************************************************** New Baccarat Game *********************************************************************************** \n         ");

        // Brand new 8 deck shoe
        Baccarat baccarat = new Baccarat();

        addStatistics(results, baccarat.statistics());// initial statistics

        BaccaratResult baccaratResult = null;
        int gameCount = 1;
        do {
            baccaratResult = baccarat.playOnce();
            if (baccaratResult.getGameResult() != GameResult.FINAL_GAME) {
                addBaccaratGameResult(results, baccaratResult, gameCount++);
                addStatistics(results, baccarat.statistics());
            }
        } while (baccaratResult.getGameResult() != GameResult.FINAL_GAME);

        results.append("Running time: " + (System.currentTimeMillis() - startTime) + " ms.");

        out.println(results.toString());
        out.close();
        System.out.println(results.toString());
    }

    /**
     * Helper to print the result.
     * @param baccaratResult
     * @param gameCount
     */
    private static void addBaccaratGameResult(StringBuffer results, BaccaratResult baccaratResult, int gameCount) {
        results.append("\n       ______________________________________________________________________   _____________________________________________________________________");
        results.append("\n       |                          Player                                     |  |                             Banker                                 |");
        results.append("\n_____________________________________________________________________________________________________________________________________________________________________");
        results.append("\n| Game |       Card 1      |       Card 2      |       Card 3      |  Points |  |       Card 1      |       Card 2      |       Card 3      | Points |    RESULT     |");
        results.append("\n_____________________________________________________________________________________________________________________________________________________________________");
        results.append("\n\n| " + leftJustify("" + gameCount, 4) + " | " + getHandAsString(baccaratResult.getPlayerHand()) + "  | " + getHandAsString(baccaratResult.getPlayerHand()) + " "
                + leftJustify("" + baccaratResult.getGameResult(), 12) + " |");
        results.append("\n_____________________________________________________________________________________________________________________________________________________________________");
    }

    /**
     * Simple method to print out the game printableResults and statistics.
     * @param stats
     */
    private static void addStatistics(StringBuffer results, BaccaratStats stats) {
        NumberFormat formatter = NumberFormat.getNumberInstance();
        results.append("\n                                 |       Banker             |       Player             |          Tie             |         TOTAL           |");
        results.append("\n\n             Odds                | " + leftJustify("" + stats.getBankerOdds(), 25) + "| " + leftJustify("" + stats.getPlayerOdds(), 25) + "| " + leftJustify("" + stats.getTieOdds(), 25) + "|"
                + "      *                  |");
        results.append("\n\n             Probability         | " + leftJustify("" + stats.getBankerWinnerProbability(), 25) + "| " + leftJustify("" + stats.getPlayerWinnnerProbability(), 25) + "| "
                + leftJustify("" + stats.getTieProbability(), 25) + "|" + leftJustify("" + (stats.getBankerWinnerProbability() + stats.getTieProbability() + stats.getPlayerWinnnerProbability()), 25) + "|");
        results.append("\n\n             Winner Combinations | " + leftJustify(formatter.format(stats.getBankerWinnerCombinations()), 25) + "| " + leftJustify(formatter.format(stats.getPlayerWinnerCombinations()), 25) + "| "
                + leftJustify(formatter.format(stats.getTieCombinations()), 25) + "|" + leftJustify(formatter.format(stats.getTotalCombinations()), 25) + "|");
        results.append("\n_____________________________________________________________________________________________________________________________________________________________________\n\n");
    }

    /**
     * Helper for the leftJustify
     * @param s
     * @param pad
     * @return padded string.
     */
    private static String leftJustify(String s, int pad) {
        return (s + "                              ").substring(0, pad);
    }

    /**
     * Helper to define a baccarat hand as string, for better printing.
     * @param hand
     * @return Baccarat Hand as string.
     */
    private static String getHandAsString(Hand hand) {
        if (hand != null) {
            StringBuffer result = new StringBuffer();
            for (Card card : hand.getCards()) {
                result.append(leftJustify(" " + card.getValue() + " " + card.getSuit() + " (" + card.getValue().getValue() + ") ", 17) + " | ");
            }
            if (hand.getCards().size() == 2) {
                result.append(leftJustify("       * ", 17) + "  |");
            }
            result.append(leftJustify(" " + hand.points(), 8) + "|");
            return result.toString();
        }
        return "";
    }

}
